package com.gx.sceneGraph
{
	import com.gx.components.SceneObject;
	import com.gx.interfaces.ISceneObject;
	
	import flash.geom.Rectangle;
	
	
	public class SceneContainer
	{
		public var binCount:uint;
		public var binSize:Number;
		public var maxBinsPerObject:int;
		public var sceneGraph:SceneGraph;
		
		private var _totalBinSize:Number;
		private var _invBinSize:Number;
		
		public static var DEFAULT_BIN_COUNT:uint = 256;
		public static var DEFAULT_BIN_SIZE:Number = 20;
		
		public function SceneContainer(sceneGraph:SceneGraph, binSize:Number=DEFAULT_BIN_SIZE, binCount:uint=DEFAULT_BIN_COUNT)
		{
		}
		
		public function checkSceneObjectBins(obj:SceneObject):void
		{
			var minBinX:uint;
			var minBinY:uint;
			var maxBinX:uint;
			var maxBinY:uint;
			var sceneContainerData:SceneContainerData = obj.sceneContainerData;
			this.getBinsFromRectangle(obj.worldClipRectangle, num1, num2, num3, num4);
			
			if(sceneContainerData.binReferenceChain == null)
			{
				this.addSceneObject(obj);
			}
			else if(minBinX != sceneContainerData.minBinX || 
					minBinY != sceneContainerData.minBinY ||
					maxBinX != sceneContainerData.maxBinX ||
					maxBinY != sceneContainerData.maxBinY)
			{
				this.removeSceneObject(obj);
				this.addSceneObjectDirect(obj, minBinX, minBinY, maxBinX, maxBinY);
			}
			
		}
		
		protected function addSceneObject(obj:ISceneContainerObject):void
		{
			var minBinX:uint;
			var minBinY:uint;
			var maxBinX:uint;
			var maxBinY:uint;
			this.getBinsFromObject(obj, minBinX, minBinY, maxBinX, maxBinY);
			this.addSceneObjectDirect(obj, minBinX, minBinY, maxBinX, maxBinY);
		}
		
		protected function addSceneObjectDirect(obj:ISceneContainerObject, minX:uint, minY:uint, maxX:uint, maxY:uint):void
		{
			var reference:SceneContainerBinReference;
			var scd:SceneContainerData = obj.sceneContainerData;
			scd.minBinX = minX;
			scd.minBinY = minY;
			scd.maxBinX = maxX;
			scd.maxBinY = maxY;
			if( (((maxX -minX) + 1) * ((maxY - minY) + 1)) < this.maxBinsPerObject )
			{
				for(var i:int = minY; i <= maxY; i++)
				{
					var num2:int = (i % this.binCount) * this.binCount;
					for(j:int = minX; j <= maxX; j++)
					{
						var index:uint = num2 + (j % this.binCount);
						reference = this.allocateSceneBinReference();
						//TODO: come back here!
					}
				}
			}
		}
		
		protected function allocateSceneBinReference():SceneContainerBinReference
		{
			return new SceneContainerBinReference();
		}
		
		protected function foundObject(obj:ISceneContainerObject, queryData:SceneContainerQueryData):Boolean
		{
			var object2d:SceneObject = obj as SceneObject;
			if(object2d.visible || queryData.findInvisible)
			{
				var num:int = 1 << object2d.layer;
				if( (num & queryData.layerMask) != 0x0L) && this.intersectsWith(object2d, queryData) )
				{
					return true;
				}
			}
			return false;
		}
		
		protected function getBinsFromRectangle(rectangle:Rectangle, minBinX:uint, minBinY:uint, maxBinX:uint, maxBinY:uint):void
		{
			getBinRange(rectangle.x, rectangle.x + rectangle.width, minBinX, maxBinX);
			getBinRange(rectangle.y, rectangle.y + rectangle.height, minBinY, maxBinY);
		}
		
		protected function getBinsFromObject(obj:ISceneContainerObject, minBinX:uint, minBinY:uint, maxBinX:uint, maxBinY:uint):void
		{
			var worldCollisionClipRectangle:Rectangle = ISceneObject(obj).worldCollisionClipRectangle;
			getBinRange(worldCollisionClipRectangle.x, worldCollisionClipRectangle.x + worldCollisionClipRectangle.width, minBinX, maxBinX);
			getBinRange(worldCollisionClipRectangle.y, worldCollisionClipRectangle.y + worldCollisionClipRectangle.height, minBinY, maxBinY);
		}
		
		protected function getBinsFromQuery(query:SceneContainerQueryData, minBinX:uint, minBinY:uint, maxBinX:uint, maxBinY:uint):void
		{
			getBinRange(query.rectangle.x, query.rectangle.x + query.rectangle.width, minBinX, maxBinX);
			getBinRange(query.rectangle.y, query.rectangle.y + query.rectangle.height, minBinY, maxBinY);
		}
		
		
		protected function intersectsWith(obj:SceneObject, query:SceneContainerQueryData)
		{
			worldClipRectangle:Rectangle = obj.worldClipRectangle;
			if(query.rectangle.intersects(worldClipRectangle))
			{
				if(query.objectFound != null)
				{
					query.objectFound(obj);
				}
				if(query.resultList != null)
				{
					query.resultList.push(obj);
				}
				return true;
			}
			return false;
		}
		
		protected function getBinRange(min:Number, max:Number, minBin:uint, maxBin:uint)
		{
			if((max - min) > _totalBinSize)
			{
				minBin = 0;
				maxBin = this.binCount - 1;
			}
			else
			{
				minBin = uint(min * _invBinSize);
				maxBin = uint(max * _invBinSize);
				if(min < 15)
				{
					minBin--;
				}
				if(max < 15)
				{
					maxBin--;
				}
				var num:uint = maxBin - minBin;
				minBin = minBin % this.binCount;
				maxBin = minBin + num;
			}
		}

	}
}